package com.wkm.chainchain.pbft.p2p;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.wkm.chainchain.pbft.common.PBFTMsgType;
import com.wkm.chainchain.pbft.common.SimulationParameterConst;
import com.wkm.chainchain.pbft.msg.PBFTMsg;
import com.wkm.chainchain.pbft.node.Node;
import com.wkm.chainchain.websocket.Client;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * @description 通过创建客户端连接本节点与P2P网络中所有节点的连接, 并保存起来进行管理
 */
@Slf4j
public class PBFTClient implements Client {
    /**
     * 单例模式获取PBFTClient
     */
    private static final PBFTClient pbftClient = new PBFTClient();

    public static PBFTClient getInstance() {
        return pbftClient;
    }

    /**
     * 保存该节点所有客户端与服务端的连接
     */
    private final List<WebSocket> sockets = new ArrayList<>();
    /**
     * 保存与消息发送客户端的连接
     */
    private WebSocketClient requestClientSockets;

    public List<WebSocket> getSockets() {
        return sockets;
    }

    public WebSocketClient getRequestClientSockets() {
        return requestClientSockets;
    }

    /**
     *连接消息发送客户端
     */
    @Override
    public void connectRequestClient() {
        try {
            requestClientSockets = new WebSocketClient(new URI("ws://localhost:" + SimulationParameterConst.CLIENT_PORT)) {

                @Override
                public void onOpen(ServerHandshake serverHandshake) {
                    log.info("已连接上消息客户端");
                    //连接上消息客户端后将当前节点的信息发送给消息客户端
                    PBFTMsg pbftMsg = new PBFTMsg();
                    Node node = new Node();
                    BeanUtil.copyProperties(Node.getInstance(), node);
                    node.setPrivateKey(null);
                    pbftMsg.setNode(node);
                    pbftMsg.setMsgType(PBFTMsgType.INIT.getCode());
                    this.send(JSON.toJSONString(pbftMsg));
                }

                @Override
                public void onMessage(String s) {
                }

                @Override
                public void onClose(int i, String s, boolean b) {
                    log.info("消息客户端关闭");
                }

                @Override
                public void onError(Exception e) {
                    log.error("消息客户端错误");
                }
            };
            requestClientSockets.connect();
        } catch (URISyntaxException e) {
            System.out.println("连接错误:" + e.getMessage());
        }
    }

    /**
     * 连接到指定的服务端
     * @param peer 格式: "ws://localhost:xxxx"
     */
    @Override
    public void connectPeer(String peer) {
        try {
            //创建一个WebSocket客户端
            final WebSocketClient socketClient = new BlockchainWebSocketClient(new URI(peer));
            //客户端 开始连接服务端
            socketClient.connect();
        } catch (URISyntaxException e) {
            System.out.println("连接错误:" + e.getMessage());
        }
    }

    /**
     * 向所有服务端广播消息
     *
     * @param message
     */
    @Override
    public void broadcast(String message) {
        if (sockets.size() == 0) {
            return;
        }

        for (WebSocket socket : sockets) {
            socket.send(message);
        }
    }

    @Override
    public void sendToOne(String message, int index) {

    }
}
